#include<iostream>
#include<sys/types.h>
#include<sys/socket.h>
#include<string>
#include<functional>
#include<cerrno>
#include<cstring>
#include<netinet/in.h>//网络需要的结构体
#include <arpa/inet.h>
#include<unistd.h>
#include<stdlib.h>

using namespace std;

typedef function<void()> func;
enum
{
    SOCKET_ERR=1,
    BIND_ERR=2,
    
};
static const string zeroip="0.0.0.0";

class udpserver
{ 
    public:
    udpserver(func func_, const uint16_t &port, const string ip = zeroip):_sockfd(-1),_func(func_), _port(port), _ip(ip)//默认参数要放最后
    {
    }

    ~udpserver(){}
    void initserver()
    {  _sockfd=socket(AF_INET,SOCK_DGRAM,0);//创建套接字
        if(_sockfd==-1)
        {
            cerr<<"socket error:"<<errno<<":"<<strerror(errno)<<endl;
            exit(SOCKET_ERR);
        }
        cout << "socket success: " << " : " << _sockfd << endl;
       //套接字绑定服务器的结构体
       struct sockaddr_in local;
       bzero(&local,sizeof(local));
       local.sin_family=AF_INET;
       local.sin_addr.s_addr=inet_addr(_ip.c_str());
       local.sin_port=htons(_port);
       int n=bind(_sockfd,(struct sockaddr*)&local,sizeof(local));
       if(n==-1)
       {
        cerr<<"bind error:"<<errno<<":"<<strerror(errno)<<endl;
        exit(BIND_ERR);
       }
    }
    void run()
    {  char buffer[1024];
        while(true)//这个循环时为了每次都创建结构体接收，因为有很多客户端发消息
        {
        struct sockaddr_in client;
        client.sin_family=AF_INET;
        socklen_t len=sizeof(client);
        int n=recvfrom(_sockfd,buffer,sizeof(buffer)-1,0,(struct sockaddr*)&client,&len);
        if(n>0)
        {buffer[n]=0;
            string message=buffer;
            uint16_t clientport=ntohs(client.sin_port);
            string clientip=inet_ntoa(client.sin_addr);//直接可以用ntoa转结构体为字符串
            //_func();
            cout << clientip << "[" << clientport << "]# " << message << endl;
        }
        }


    }


    private:
    int _sockfd;
    string _ip;
    uint16_t _port;
    func  _func;

};
